home *** CD-ROM | disk | FTP | other *** search
/ Chip: Internet / Chip Internet.iso / viewer / ghost / print.c < prev    next >
C/C++ Source or Header  |  1993-07-29  |  24KB  |  824 lines

  1. /*
  2.  * print.c --   Printing operations for GSVIEW.EXE, 
  3.  *              a graphical interface for MS-Windows Ghostscript
  4.  * Copyright (C) 1993  Russell Lang
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   Author: Russell Lang
  21.  * Internet: rjl@monu1.cc.monash.edu.au
  22.  */
  23.  
  24. #define STRICT
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #include <commdlg.h>
  28. #include <shellapi.h>
  29. #include <mmsystem.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include <dir.h>
  35. #include <io.h>
  36. #define NeedFunctionPrototypes 1
  37. #include "ps.h"
  38. #include "gsview.h"
  39.  
  40. static char pcfname[MAXSTR];    /* name of temporary command file for printing */
  41. static char pfname[MAXSTR];    /* name of temporary file for printing options */
  42. int gp_printfile(char *filename, char *port);
  43.  
  44. /* documented in Device Driver Adaptation Guide */
  45. /* Prototypes taken from print.h */
  46. DECLARE_HANDLE(HPJOB);
  47.  
  48. HPJOB   WINAPI OpenJob(LPSTR, LPSTR, HPJOB);
  49. int     WINAPI StartSpoolPage(HPJOB);
  50. int     WINAPI EndSpoolPage(HPJOB);
  51. int     WINAPI WriteSpool(HPJOB, LPSTR, int);
  52. int     WINAPI CloseJob(HPJOB);
  53. int     WINAPI DeleteJob(HPJOB, int);
  54. int     WINAPI WriteDialog(HPJOB, LPSTR, int);
  55. int     WINAPI DeleteSpoolPage(HPJOB);
  56.  
  57. struct prop_item_s {
  58.     char    name[MAXSTR];
  59.     char    value[MAXSTR];
  60. };
  61.  
  62. char not_defined[] = "[Not defined]";
  63.  
  64. struct prop_item_s *
  65. get_properties(char *device)
  66. {
  67. char *entries, *p;
  68. int i, numentry;
  69. struct prop_item_s *proplist;
  70.     entries = malloc(PROFILE_SIZE);
  71.     if (entries == (char *)NULL)
  72.        return NULL;
  73.     GetPrivateProfileString(device, NULL, "", entries, PROFILE_SIZE, INIFILE);
  74.     if (strlen(entries) == 0) {
  75.         free(entries);
  76.         return NULL;
  77.     }
  78.     p = entries;
  79.     for (numentry=0; p!=(char *)NULL && strlen(p)!=0; numentry++)
  80.         p += strlen(p) + 1;
  81.     proplist = (struct prop_item_s *)malloc((numentry+1) * sizeof(struct prop_item_s));
  82.     if (proplist == (struct prop_item_s *)NULL) {
  83.         free(entries);
  84.         return NULL;
  85.     }
  86.     p = entries;
  87.     for (i=0; i<numentry; i++) {
  88.         strcpy(proplist[i].name, p);
  89.         GetPrivateProfileString(device, p, "", proplist[i].value, sizeof(proplist->value), INIFILE);
  90.         p += strlen(p) + 1;
  91.     }
  92.     proplist[numentry].name[0] = '\0';
  93.     proplist[numentry].value[0] = '\0';
  94.     free(entries);
  95.     return proplist;
  96. }
  97.  
  98. /* dialog box for selecting printer properties */
  99. BOOL CALLBACK _export
  100. PropDlgProc(HWND hDlg, UINT wmsg, WPARAM wParam, LPARAM lParam)
  101. {
  102.     char buf[128];
  103.     int iprop;
  104.     int ivalue;
  105.     WORD notify_message;
  106.     char *p;
  107.     char *value;
  108.     static char device[MAXSTR];    /* contains printer device name */
  109.     static struct prop_item_s* propitem;
  110.     char section[MAXSTR];
  111.  
  112.     switch (wmsg) {
  113.         case WM_INITDIALOG:
  114.         lstrcpy(device, (LPSTR)lParam);    /* initialise device name */
  115.         propitem = get_properties(device);
  116.         if (propitem == (struct prop_item_s *)NULL) {
  117.             EndDialog(hDlg, FALSE);
  118.             return TRUE;
  119.         }
  120.         for (iprop=0; propitem[iprop].name[0]; iprop++) {
  121.             SendDlgItemMessage(hDlg, PROP_NAME, CB_ADDSTRING, 0, 
  122.             (LPARAM)((LPSTR)propitem[iprop].name+1));
  123.         }
  124.         SendDlgItemMessage(hDlg, PROP_NAME, CB_SETCURSEL, 0, 0L);
  125.         /* force update of PROP_VALUE */
  126.         SendDlgNotification(hDlg, PROP_NAME, CBN_SELCHANGE);
  127.         return TRUE;
  128.         case WM_COMMAND:
  129.         notify_message = GetNotification(wParam,lParam);
  130.         switch (LOWORD(wParam)) {
  131.             case ID_HELP:
  132.                 SendMessage(hwndimg, help_message, 0, 0L);
  133.                 return(FALSE);
  134.             case PROP_NAME:
  135.             if (notify_message != CBN_SELCHANGE) {
  136.                 return FALSE;
  137.             }
  138.             iprop = (int)SendDlgItemMessage(hDlg, PROP_NAME, CB_GETCURSEL, 0, 0L);
  139.             if (iprop == CB_ERR) {
  140.                 return FALSE;
  141.             }
  142.             /* now look up entry in gsview.ini */
  143.             /* and update PROP_VALUE list box */
  144.             strcpy(section, device);
  145.             strcat(section, " values");
  146.             GetPrivateProfileString(section, propitem[iprop].name, "", buf, sizeof(buf)-2, INIFILE);
  147.             buf[strlen(buf)+1] = '\0';    /* put double NULL at end */
  148.                 SendDlgItemMessage(hDlg, PROP_VALUE, CB_RESETCONTENT, 0, 0L);
  149.                 SendDlgItemMessage(hDlg, PROP_VALUE, CB_ADDSTRING, 0, 
  150.                 (LPARAM)((LPSTR)not_defined));
  151.             p = buf;
  152.             if (*p != '\0') {
  153.               EnableWindow(GetDlgItem(hDlg, PROP_VALUE), TRUE);
  154.               while (*p!='\0') {
  155.                 value = p;
  156.                 while ((*p!='\0') && (*p!=','))
  157.                 p++;
  158.                 *p++ = '\0';
  159.                     SendDlgItemMessage(hDlg, PROP_VALUE, CB_ADDSTRING, 0, 
  160.                     (LPARAM)((LPSTR)value));
  161.               }
  162.             }
  163.             SendDlgItemMessage(hDlg, PROP_VALUE, CB_SELECTSTRING, -1, (LPARAM)(LPSTR)propitem[iprop].value);
  164.                 SetDlgItemText(hDlg, PROP_VALUE, propitem[iprop].value);
  165.             return FALSE;
  166.             case PROP_VALUE:
  167.             if (notify_message == CBN_SELCHANGE) {
  168.                 iprop = (int)SendDlgItemMessage(hDlg, PROP_NAME, CB_GETCURSEL, 0, 0L);
  169.                 if (iprop == CB_ERR)
  170.                     return FALSE;
  171.                 ivalue = (int)SendDlgItemMessage(hDlg, PROP_VALUE, CB_GETCURSEL, 0, 0L);
  172.                 if (ivalue == CB_ERR)
  173.                     return FALSE;
  174.                 SendDlgItemMessage(hDlg, PROP_VALUE, CB_GETLBTEXT, ivalue, (LPARAM)(LPSTR)propitem[iprop].value);
  175.             }
  176.             if (notify_message == CBN_EDITCHANGE) {
  177.                 iprop = (int)SendDlgItemMessage(hDlg, PROP_NAME, CB_GETCURSEL, 0, 0L);
  178.                 if (iprop == CB_ERR)
  179.                     return FALSE;
  180.                     GetDlgItemText(hDlg, PROP_VALUE, (LPSTR)propitem[iprop].value, sizeof(propitem->value));
  181.             }
  182.             return FALSE;
  183.             case IDOK:
  184.             for (iprop=0; propitem[iprop].name[0]; iprop++) {
  185.                 WritePrivateProfileString(device, propitem[iprop].name, propitem[iprop].value, INIFILE);
  186.             }
  187.             free((char *)propitem);
  188.             EndDialog(hDlg, TRUE);
  189.             return TRUE;
  190.             case IDCANCEL:
  191.             free((char *)propitem);
  192.             EndDialog(hDlg, FALSE);
  193.             return TRUE;
  194.         }
  195.         break;
  196.     }
  197.     return FALSE;
  198. }
  199.  
  200.  
  201. /* dialog box for selecting printer device and resolution */
  202. BOOL CALLBACK _export
  203. DeviceDlgProc(HWND hDlg, UINT wmsg, WPARAM wParam, LPARAM lParam)
  204. {
  205.     char buf[128];
  206.     int idevice;
  207.     WORD notify_message;
  208.     char *p;
  209.     char *res;
  210.     int numentry;
  211.     char entry[MAXSTR];
  212.     struct prop_item_s *proplist;
  213.  
  214.     switch (wmsg) {
  215.         case WM_INITDIALOG:
  216.         p = get_devices();
  217.         res = p;    /* save for free() */
  218.         for (numentry=0; p!=(char *)NULL && strlen(p)!=0; numentry++) {
  219.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_ADDSTRING, 0, 
  220.             (LPARAM)((LPSTR)p));
  221.             p += strlen(p) + 1;
  222.         }
  223.         free(res);
  224.         if (SendDlgItemMessage(hDlg, DEVICE_NAME, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)device_name)
  225.             == CB_ERR)
  226.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_SETCURSEL, 0, 0L);
  227.         /* force update of DEVICE_RES */
  228.         SendDlgNotification(hDlg, DEVICE_NAME, CBN_SELCHANGE);
  229.         if (SendDlgItemMessage(hDlg, DEVICE_RES, CB_SELECTSTRING, 0, (LPARAM)(LPSTR)device_resolution)
  230.             == CB_ERR)
  231.             SendDlgItemMessage(hDlg, DEVICE_RES, CB_SETCURSEL, 0, 0L);
  232.         return TRUE;
  233.         case WM_COMMAND:
  234.         notify_message = GetNotification(wParam,lParam);
  235.         switch (LOWORD(wParam)) {
  236.             case ID_HELP:
  237.                 SendMessage(hwndimg, help_message, 0, 0L);
  238.                 return(FALSE);
  239.             case DEVICE_NAME:
  240.             if (notify_message != CBN_SELCHANGE) {
  241.                 return FALSE;
  242.             }
  243.             idevice = (int)SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETCURSEL, 0, 0L);
  244.             if (idevice == CB_ERR) {
  245.                 return FALSE;
  246.             }
  247.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETLBTEXT, idevice, (LPARAM)(LPSTR)entry);
  248.             if ( (proplist = get_properties(entry)) != (struct prop_item_s *)NULL ) {
  249.                     free((char *)proplist);
  250.                 EnableWindow(GetDlgItem(hDlg, DEVICE_PROP), TRUE);
  251.             }
  252.             else
  253.                 EnableWindow(GetDlgItem(hDlg, DEVICE_PROP), FALSE);
  254.             /* now look up entry in gsview.ini */
  255.             /* and update DEVICE_RES list box */
  256.             GetPrivateProfileString(DEVSECTION, entry, "", buf, sizeof(buf)-2, INIFILE);
  257.             buf[strlen(buf)+1] = '\0';    /* double NULL at end */
  258.                 SendDlgItemMessage(hDlg, DEVICE_RES, CB_RESETCONTENT, 0, 0L);
  259.             p = buf;
  260.             if (*p == '\0') {
  261.                 /* no resolutions can be set */
  262.                 EnableWindow(GetDlgItem(hDlg, DEVICE_RES), FALSE);
  263.                 EnableWindow(GetDlgItem(hDlg, DEVICE_RESTEXT), FALSE);
  264.             }
  265.             else {
  266.               EnableWindow(GetDlgItem(hDlg, DEVICE_RES), TRUE);
  267.               EnableWindow(GetDlgItem(hDlg, DEVICE_RESTEXT), TRUE);
  268.               while (*p!='\0') {
  269.                 res = p;
  270.                 while ((*p!='\0') && (*p!=','))
  271.                 p++;
  272.                 *p++ = '\0';
  273.                     SendDlgItemMessage(hDlg, DEVICE_RES, CB_ADDSTRING, 0, 
  274.                     (LPARAM)((LPSTR)res));
  275.               }
  276.             }
  277.             SendDlgItemMessage(hDlg, DEVICE_RES, CB_SETCURSEL, 0, 0L);
  278.             if (SendDlgItemMessage(hDlg, DEVICE_RES, CB_GETLBTEXT, 0, (LPARAM)(LPSTR)buf)
  279.                 != CB_ERR)
  280.                     SetDlgItemText(hDlg, DEVICE_RES, buf);
  281.             return FALSE;
  282.             case DEVICE_RES:
  283.             /* don't have anything to do */
  284.             return FALSE;
  285.             case DEVICE_PROP:
  286.             idevice = (int)SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETCURSEL, 0, 0L);
  287.             if (idevice == CB_ERR) {
  288.                 return FALSE;
  289.             }
  290.             SendDlgItemMessage(hDlg, DEVICE_NAME, CB_GETLBTEXT, idevice, (LPARAM)(LPSTR)entry);
  291.             if ( (proplist = get_properties(entry)) != (struct prop_item_s *)NULL ) {
  292.                     DLGPROC lpProcProp;
  293.                     free((char *)proplist);
  294.                 LoadString(phInstance, IDS_TOPICPRINT, szHelpTopic, sizeof(szHelpTopic));
  295.                 lpProcProp = (DLGPROC)MakeProcInstance((FARPROC)PropDlgProc, phInstance);
  296.                 DialogBoxParam( phInstance, "PropDlgBox", hDlg, lpProcProp, (LPARAM)entry);
  297.                 FreeProcInstance((FARPROC)lpProcProp);
  298.             }
  299.             else
  300.                 play_sound(SOUND_ERROR);
  301.             return FALSE;
  302.             case IDOK:
  303.             /* save device name and resolution */
  304.                 GetDlgItemText(hDlg, DEVICE_NAME, device_name, sizeof(device_name));
  305.                 GetDlgItemText(hDlg, DEVICE_RES, device_resolution, sizeof(device_resolution));
  306.             EndDialog(hDlg, TRUE);
  307.             return TRUE;
  308.             case IDCANCEL:
  309.             EndDialog(hDlg, FALSE);
  310.             return TRUE;
  311.         }
  312.         break;
  313.     }
  314.     return FALSE;
  315. }
  316.  
  317.  
  318. /* Modeless dialog box - Cancel printing */
  319. BOOL CALLBACK _export
  320. CancelDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  321. {
  322.     switch(message) {
  323.     case WM_INITDIALOG:
  324.         SetWindowText(hDlg, szAppName);
  325.         return TRUE;
  326.     case WM_COMMAND:
  327.         switch(LOWORD(wParam)) {
  328.         case IDCANCEL:
  329.             DestroyWindow(hDlg);
  330.             hDlgModeless = 0;
  331.             EndDialog(hDlg, 0);
  332.             return TRUE;
  333.         }
  334.     }
  335.     return FALSE;
  336. }
  337.  
  338. /* Dialog box to select printer port */
  339. BOOL CALLBACK _export
  340. SpoolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  341. {
  342. LPSTR entry;
  343.     switch(message) {
  344.     case WM_INITDIALOG:
  345.         entry = (LPSTR)lParam;
  346.         while (*entry) {
  347.         SendDlgItemMessage(hDlg, SPOOL_PORT, LB_ADDSTRING, 0, (LPARAM)entry);
  348.         entry += lstrlen(entry)+1;
  349.         }
  350.         SendDlgItemMessage(hDlg, SPOOL_PORT, LB_SETCURSEL, 0, (LPARAM)0);
  351.         return TRUE;
  352.     case WM_COMMAND:
  353.         switch(LOWORD(wParam)) {
  354.         case SPOOL_PORT:
  355. #ifdef WIN32
  356.             if (HIWORD(wParam)
  357. #else
  358.             if (HIWORD(lParam)
  359. #endif
  360.                            == LBN_DBLCLK)
  361.             PostMessage(hDlg, WM_COMMAND, IDOK, 0L);
  362.             return FALSE;
  363.         case IDOK:
  364.             EndDialog(hDlg, 1+(int)SendDlgItemMessage(hDlg, SPOOL_PORT, LB_GETCURSEL, 0, 0L));
  365.             return TRUE;
  366.         case IDCANCEL:
  367.             EndDialog(hDlg, 0);
  368.             return TRUE;
  369.         }
  370.     }
  371.     return FALSE;
  372. }
  373.  
  374. /* Print File to port */
  375. /* port==NULL means prompt for port with dialog box */
  376. int
  377. gp_printfile(char *filename, char *port)
  378. {
  379. #define PRINT_BUF_SIZE 16384u
  380. char *buffer;
  381. char *portname;
  382. DLGPROC lpfnSpoolProc;
  383. int i, iport;
  384. HPJOB hJob;
  385. WORD count;
  386. FILE *f;
  387. int error = FALSE;
  388. DLGPROC lpfnCancelProc;
  389. long lsize;
  390. long ldone;
  391. char fmt[MAXSTR];
  392. char pcdone[10];
  393. MSG msg;
  394.  
  395.     if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
  396.         return FALSE;
  397.     if (port == (char *)NULL) {
  398.         /* get list of ports */
  399.         GetProfileString("ports", NULL, "", buffer, PRINT_BUF_SIZE);
  400.         /* select a port */
  401.         lpfnSpoolProc = (DLGPROC)MakeProcInstance((FARPROC)SpoolDlgProc, phInstance);
  402.         iport = DialogBoxParam(phInstance, "SpoolDlgBox", hwndtext, lpfnSpoolProc, (LPARAM)buffer);
  403.         FreeProcInstance((FARPROC)lpfnSpoolProc);
  404.         if (!iport) {
  405.         free(buffer);
  406.         return FALSE;
  407.         }
  408.         portname = buffer;
  409.         for (i=1; i<iport && strlen(portname)!=0; i++)
  410.         portname += lstrlen(portname)+1;
  411.     }
  412.     else
  413.         portname = port;
  414.     
  415.     if ((f = fopen(filename, "rb")) == (FILE *)NULL) {
  416.         free(buffer);
  417.         return FALSE;
  418.     }
  419.     fseek(f, 0L, SEEK_END);
  420.     lsize = ftell(f);
  421.     if (lsize <= 0)
  422.         lsize = 1;
  423.     fseek(f, 0L, SEEK_SET);
  424.  
  425.     hJob = OpenJob(portname, filename, (HDC)NULL);
  426.     switch ((int)hJob) {
  427.         case SP_APPABORT:
  428.         case SP_ERROR:
  429.         case SP_OUTOFDISK:
  430.         case SP_OUTOFMEMORY:
  431.         case SP_USERABORT:
  432.             fclose(f);
  433.         free(buffer);
  434.             return FALSE;
  435.     }
  436.     if (StartSpoolPage(hJob) < 0)
  437.         error = TRUE;
  438.  
  439.     lpfnCancelProc = (DLGPROC)MakeProcInstance((FARPROC)CancelDlgProc, phInstance);
  440.     hDlgModeless = CreateDialog(phInstance, "CancelDlgBox", hwndimg, lpfnCancelProc);
  441.     ldone = 0;
  442.     LoadString(phInstance, IDS_CANCELDONE, fmt, sizeof(fmt));
  443.  
  444.     while (!error && hDlgModeless 
  445.       && (count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0 ) {
  446.         if (WriteSpool(hJob, buffer, count) < 0)
  447.         error = TRUE;
  448.         ldone += count;
  449.         sprintf(pcdone, fmt, (int)(ldone * 100 / lsize));
  450.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), pcdone);
  451.         while (PeekMessage(&msg, hDlgModeless, 0, 0, PM_REMOVE)) {
  452.             if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  453.             TranslateMessage(&msg);
  454.             DispatchMessage(&msg);
  455.         }
  456.         }
  457.     }
  458.     free(buffer);
  459.     fclose(f);
  460.  
  461.     if (!hDlgModeless)
  462.         error=TRUE;
  463.     DestroyWindow(hDlgModeless);
  464.     hDlgModeless = 0;
  465.     FreeProcInstance((FARPROC)lpfnCancelProc);
  466.     EndSpoolPage(hJob);
  467.     if (error)
  468.         DeleteJob(hJob, 0);
  469.     else
  470.         CloseJob(hJob);
  471.     return !error;
  472. }
  473.  
  474.  
  475. /* get a filename and spool it for printing */
  476. void
  477. gsview_spool(char *fname, char *port)
  478. {
  479.     static char filename[MAXSTR];
  480.  
  481.     if (fname == (char *)NULL) {
  482.         if (!getfilename(filename, OPEN, FILTER_ALL, IDS_PRINTFILE, IDS_TOPICPRINT))
  483.         return;
  484.     }
  485.     else {
  486.         while (*fname && *fname==' ')
  487.             fname++;
  488.         strncpy(filename, fname, MAXSTR);
  489.     }
  490.  
  491.     if (!gp_printfile(filename, port)) {
  492.         play_sound(SOUND_ERROR);
  493.         return;
  494.     }
  495. }
  496.  
  497.  
  498. char *
  499. get_devices()
  500. {
  501. HGLOBAL hglobal;
  502. LPSTR device;
  503. LPSTR lp;
  504. char *p;
  505.     p = malloc(PROFILE_SIZE);
  506.     if (p == (char *)NULL)
  507.         return (char *)NULL;
  508.  
  509.     GetPrivateProfileString(DEVSECTION, NULL, "", p, PROFILE_SIZE, INIFILE);
  510.     if (strlen(p) == 0) {
  511.         /* [Devices] section doesn't exist.  Initialise from resources */
  512.         hglobal = LoadResource(phInstance, FindResource(phInstance, "gsview_devices", RT_RCDATA));
  513.         if ( (device = (LPSTR)LockResource(hglobal)) == (LPSTR)NULL)
  514.         return (char *)NULL;
  515.         while (lstrlen(device)!=0) {
  516.             for (lp = device; (*lp!='\0') && (*lp!=','); lp++)
  517.                 /* nothing */;
  518.         *lp++ = '\0';
  519.         WritePrivateProfileString(DEVSECTION, device, lp, INIFILE);
  520.         device = lp + lstrlen(lp) + 1;
  521.         }
  522.         FreeResource(hglobal);
  523.     }
  524.     GetPrivateProfileString(DEVSECTION, NULL, "", p, PROFILE_SIZE, INIFILE);
  525.     return p;
  526. }
  527.  
  528. /* cleanup print temporary files */
  529. void
  530. print_cleanup(void)
  531. {
  532.     if ((pcfname[0] != '\0') && !debug)
  533.         unlink(pcfname);
  534.     pcfname[0] = '\0';
  535.     if ((pfname[0] != '\0') && !debug)
  536.         unlink(pfname);
  537.     pfname[0] = '\0';
  538. }
  539.  
  540. /* print a range of pages using a Ghostscript device */
  541. void
  542. gsview_print(BOOL to_file)
  543. {
  544.     int i;
  545.     BOOL flag;
  546.     DLGPROC lpProcDevice;
  547.     float print_xdpi, print_ydpi;
  548.     int width, height;
  549.  
  550.     struct prop_item_s *proplist;
  551.     
  552.     static char output[MAXSTR];    /* output filename for printing */
  553.     char *fname;            /* filename to print */
  554.     char command[256];
  555.     FILE *pcfile;
  556.     FILE *optfile;
  557.     int pages;
  558.     int thispage = pagenum;
  559.  
  560.     if (dfname[0] == '\0') {
  561.         gserror(IDS_NOTOPEN, NULL, MB_ICONEXCLAMATION, SOUND_NOTOPEN);
  562.         return;
  563.     }
  564.     
  565.     LoadString(phInstance, IDS_TOPICPRINT, szHelpTopic, sizeof(szHelpTopic));
  566.     lpProcDevice = (DLGPROC)MakeProcInstance((FARPROC)DeviceDlgProc, phInstance);
  567.     flag = DialogBoxParam( phInstance, "DeviceDlgBox", hwndimg, lpProcDevice, (LPARAM)NULL);
  568.     FreeProcInstance((FARPROC)lpProcDevice);
  569.     if (!flag) {
  570.         return;
  571.     }
  572.  
  573.     info_wait(TRUE);
  574.     gswin_close();    /* we need a new Ghostscript */
  575.     info_wait(FALSE);
  576.  
  577.     fname = (char *)NULL;
  578.     if (doc == (struct document *)NULL) {
  579.         play_sound(SOUND_NONUMBER);
  580.             LoadString(phInstance, IDS_PRINTINGALL, command, sizeof(command));
  581.         if (MessageBox(hwndimg, command, szAppName, MB_OKCANCEL | MB_ICONINFORMATION) == IDCANCEL)
  582.             return;
  583.         fname = dfname;
  584.         pages = 1;
  585.     }
  586.     else {
  587.         pages = 1;
  588.         if (doc->numpages != 0) {
  589.         if (!get_page(&thispage, TRUE))
  590.             return;
  591.             pages = 0;
  592.             for (i=0; i< doc->numpages; i++) {
  593.                 if (page_list.select[i]) pages++;
  594.             }
  595.         }
  596.  
  597.         if ((pcfname[0] != '\0') && !debug)
  598.         unlink(pcfname);
  599.         pcfname[0] = '\0';
  600.         if ( (pcfile = gp_open_scratch_file(szScratch, pcfname, "w")) == (FILE *)NULL) {
  601.         play_sound(SOUND_ERROR);
  602.         return;
  603.         }
  604.         pscopydoc(pcfile);
  605.         fclose(pcfile);
  606.         fname = pcfname;
  607.     }
  608.     
  609.     if (to_file) {
  610.         if (!getfilename(output, SAVE, FILTER_ALL, IDS_OUTPUTFILE, IDS_TOPICPRINT))
  611.         return;
  612.     }
  613.  
  614.     /* calculate image size */
  615.     switch (sscanf(device_resolution,"%fx%f", &print_xdpi, &print_ydpi)) {
  616.         case EOF:
  617.         case 0:
  618.             print_xdpi = print_ydpi = DEFAULT_RESOLUTION;
  619.             break;
  620.         case 1:
  621.             print_ydpi = print_xdpi;
  622.     }
  623.     i = get_papersizes_index();
  624.     if (i < 0) {
  625.         width = user_width;
  626.         width = user_height;
  627.     }
  628.     else {
  629.         width = papersizes[i].width;
  630.         height = papersizes[i].height;
  631.     }
  632.     width  = (unsigned int)(width  / 72.0 * print_xdpi);
  633.     height = (unsigned int)(height / 72.0 * print_ydpi);
  634.  
  635.  
  636.     if ((pfname[0] != '\0') && !debug)
  637.         unlink(pfname);
  638.     pfname[0] = '\0';
  639.     if ( (optfile = gp_open_scratch_file(szScratch, pfname, "w")) == (FILE *)NULL) {
  640.         play_sound(SOUND_ERROR);
  641.         return;
  642.     }
  643.     fprintf(optfile, "-dNOPAUSE\n");
  644.     if (safer)
  645.         fprintf(optfile, "-dSAFER\n");
  646.     fprintf(optfile, "-sDEVICE=%s\n",device_name);
  647.     fprintf(optfile, "-r%gx%g\n", (double)print_xdpi, (double)print_ydpi);
  648.     fprintf(optfile, "-g%ux%u\n",width,height);
  649.     if (to_file) {
  650.         char *p;
  651.         fprintf(optfile, "-sOutputFile=");
  652.         for (p=output; *p != '\0'; p++)
  653.             if (*p == '\\')
  654.                 fputc('/',optfile);
  655.             else
  656.                 fputc(*p,optfile);
  657.         fputc('\n',optfile);
  658.     }
  659.     if ((proplist = get_properties(device_name)) != (struct prop_item_s *)NULL) {
  660.         /* output current property selections */
  661.         for (i=0; proplist[i].name[0]; i++) {
  662.         if (strcmp(proplist[i].value, not_defined) != 0)
  663.             fprintf(optfile,"-%s=%s\n", proplist[i].name, proplist[i].value);
  664.         }
  665.         free((char *)proplist);
  666.     }
  667.     fclose(optfile);
  668.  
  669.     sprintf(command,"%s -sGSVIEW=%u @%s %s quit.ps", szGSwin,
  670.         (unsigned int)hwndimg, pfname, fname);
  671.  
  672.     if (strlen(command) > 126) {
  673.         /* command line too long */
  674.         gserror(IDS_TOOLONG, command, MB_ICONSTOP, SOUND_ERROR);
  675.         unlink(pfname);
  676.         pfname[0] = '\0';
  677.         gswin_hinst = (HINSTANCE)NULL;
  678.         return;
  679.     }
  680.     info_wait(TRUE);
  681.     gswin_hinst = (HINSTANCE)WinExec(command, SW_SHOWMINNOACTIVE);
  682.  
  683.     if (gswin_hinst < HINSTANCE_ERROR) {
  684.         gserror(IDS_CANNOTRUN, command, MB_ICONSTOP, SOUND_ERROR);
  685.         unlink(pfname);
  686.         pfname[0] = '\0';
  687.         info_wait(FALSE);
  688.         gswin_hinst = (HINSTANCE)NULL;
  689.         return;
  690.     }
  691.  
  692.     set_timer(timeout*pages);
  693.     info_wait(TRUE);
  694.     return;
  695. }
  696.  
  697. /* extract a range of pages for later printing */
  698. void
  699. gsview_extract()
  700. {
  701.     FILE *f;
  702.     static char output[MAXSTR];
  703.     int thispage = pagenum;
  704.  
  705.     if (dfname[0] == '\0') {
  706.         gserror(IDS_NOTOPEN, NULL, MB_ICONEXCLAMATION, SOUND_NOTOPEN);
  707.         return;
  708.     }
  709.  
  710.     if (doc == (struct document *)NULL) {
  711.         gserror(IDS_NOPAGE, NULL, MB_ICONEXCLAMATION, SOUND_NONUMBER);
  712.         return;
  713.     }
  714.     
  715.     if (doc->numpages != 0)
  716.         if (!get_page(&thispage, TRUE))
  717.             return;
  718.  
  719.     if (!getfilename(output, SAVE, FILTER_PS, NULL, IDS_TOPICPRINT))
  720.         return;
  721.  
  722.     if ((f = fopen(output, "wb")) == (FILE *)NULL) {
  723.         return;
  724.     }
  725.  
  726.     info_wait(TRUE);
  727.     if (doc->numpages != 0)
  728.         pscopydoc(f);
  729.     else
  730.         pscopy(dfile, f, doc->beginheader, doc->endtrailer);
  731.  
  732.     fclose(f);
  733.  
  734.     info_wait(FALSE);
  735.     return;
  736. }
  737.  
  738. /* pscopydoc is copied (with modifications) from ghostview misc.c */
  739. /* Copyright (C) 1992  Timothy O. Theisen */
  740. /* length calculates string length at compile time */
  741. /* can only be used with character constants */
  742. #define length(a) (sizeof(a)-1)
  743.  
  744. /* Copy the headers, marked pages, and trailer to fp */
  745. void
  746. pscopydoc(FILE *fp)
  747. {
  748.     char text[PSLINELENGTH];
  749.     char *comment;
  750.     BOOL pages_written = FALSE;
  751.     BOOL pages_atend = FALSE;
  752.     int pages = 0;
  753.     int page = 1;
  754.     int i;
  755.     long here;
  756.  
  757.     for (i=0; i< doc->numpages; i++) {
  758.         if (page_list.select[i]) pages++;
  759.     }
  760.  
  761.     here = doc->beginheader;
  762.     while ( (comment = pscopyuntil(dfile, fp, here,
  763.                doc->endheader, "%%Pages:")) != (char *)NULL ) {
  764.     here = ftell(dfile);
  765.     if (pages_written || pages_atend) {
  766.         free(comment);
  767.         continue;
  768.     }
  769.     sscanf(comment+length("%%Pages:"), "%s", text);
  770.     if (strcmp(text, "(atend)") == 0) {
  771.         fputs(comment, fp);
  772.         pages_atend = TRUE;
  773.     } else {
  774.         switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  775.         case 1:
  776.             fprintf(fp, "%%%%Pages: %d %d\r\n", pages, i);
  777.             break;
  778.         default:
  779.             fprintf(fp, "%%%%Pages: %d\r\n", pages);
  780.             break;
  781.         }
  782.         pages_written = TRUE;
  783.     }
  784.     free(comment);
  785.     }
  786.     pscopy(dfile, fp, doc->beginpreview, doc->endpreview);
  787.     pscopy(dfile, fp, doc->begindefaults, doc->enddefaults);
  788.     pscopy(dfile, fp, doc->beginprolog, doc->endprolog);
  789.     pscopy(dfile, fp, doc->beginsetup, doc->endsetup);
  790.  
  791.     page = 1;
  792.     for (i = 0; i < doc->numpages; i++) {
  793.     if (page_list.select[map_page(i)])  {
  794.         comment = pscopyuntil(dfile, fp, doc->pages[i].begin,
  795.                   doc->pages[i].end, "%%Page:");
  796.         fprintf(fp, "%%%%Page: %s %d\r\n",
  797.             doc->pages[i].label, page++);
  798.         free(comment);
  799.         pscopy(dfile, fp, -1, doc->pages[i].end);
  800.     }
  801.     }
  802.  
  803.     here = doc->begintrailer;
  804.     while ( (comment = pscopyuntil(dfile, fp, here,
  805.                doc->endtrailer, "%%Pages:")) != (char *)NULL ) {
  806.     here = ftell(dfile);
  807.     if (pages_written) {
  808.         free(comment);
  809.         continue;
  810.     }
  811.     switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
  812.         case 1:
  813.         fprintf(fp, "%%%%Pages: %d %d\r\n", pages, i);
  814.         break;
  815.         default:
  816.         fprintf(fp, "%%%%Pages: %d\r\n", pages);
  817.         break;
  818.     }
  819.     pages_written = TRUE;
  820.     free(comment);
  821.     }
  822. }
  823. #undef length
  824.